package com.smarttiger.zero.admin.controller;

import cn.hutool.cache.impl.LRUCache;
import com.alibaba.fastjson.JSON;
import com.smarttiger.zero.admin.entity.BaseEntity;
import com.smarttiger.zero.admin.util.Message;
import com.smarttiger.zero.admin.util.ZEROCacheUtil;
import com.smarttiger.zero.admin.util.ParamNames;
import com.smarttiger.zero.admin.util.SpringContextUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 接口类
 * author zhengwei.zhou
 */
@RestController
@RequestMapping(value = "/zero-admin")
public class WebController {

    public static final String COM_HONHAND_ZERO_ADMIN_SERVICE = "com.smarttiger.zero.admin.service.";
    public static final String COM_HONHAND_ZERO_ADMIN_ENTITY = "com.smarttiger.zero.admin.entity.";

    /**
     * model查询通用方法
     * @param model 实体名称
     * @param method 方法名称
     * @param paramMap 参数list,每个参数必须是String
     * @return
     */
    @RequestMapping(value = "/model/{model}/{method}/query")
    public Message queryEntity(@PathVariable String  model,
                           @PathVariable String method,
                           @RequestBody(required=false) Map<String,Object> paramMap
                           ){
        Message message = new Message();
        Object beanService = SpringContextUtils.getBean(model+"Service");
        try {
            model = (new StringBuilder()).append(Character.toUpperCase(model.charAt(0))).append(model.substring(1)).toString();
            Class clazz = getClass(COM_HONHAND_ZERO_ADMIN_SERVICE +model+"Service");

            Method exMethod = null;
            if(paramMap != null && paramMap.size()>0){
                Class<String>[] classes= new Class[paramMap.size()];
                for (int i = 0; i < classes.length; i++) {
                    classes[i]  = String.class;
                }
                exMethod = clazz.getMethod(method, classes);
            }else{
                exMethod = clazz.getMethod(method, null);
            }

            if(exMethod != null){
                if(paramMap == null || paramMap.size()==0){
                    Object invoke = exMethod.invoke(beanService);
                    if(invoke instanceof Message){
                        return (Message) invoke;
                    }
                    message.setCode("1");
                    message.setData(invoke);
                }else{
                    ParamNames annotation = exMethod.getAnnotation(ParamNames.class);
                    String value = annotation.value();
                    String[] parameters = value.split(",");
                    List<String> paramList = new ArrayList<>();
                    for (String parameter : parameters) {
                        paramList.add(paramMap.get(parameter).toString());
                    }
                    String[] strArr = paramList.toArray(new String[paramMap.size()]);
                    Object invoke = exMethod.invoke(beanService,strArr);
                    if(invoke instanceof Message){
                        return (Message) invoke;
                    }
                    message.setCode("1");
                    message.setData(invoke);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            message.setCode("0");
        }
        return message;
    }


    /**
     * 通过example查询
     * @param model
     * @param paramMap
     * @return
     */
    @RequestMapping(value = "/model/{model}/findByExample/query")
    public Message findByExample(@PathVariable String  model,
                           @RequestBody(required=false) Map<String,Object> paramMap
                           ){
        Message message = new Message();
        Object beanService = SpringContextUtils.getBean(model+"Service");
        try {
            model = (new StringBuilder()).append(Character.toUpperCase(model.charAt(0))).append(model.substring(1)).toString();
            Class clazz = getClass(COM_HONHAND_ZERO_ADMIN_SERVICE+model+"Service");
            Class clazzModel = getClass(COM_HONHAND_ZERO_ADMIN_ENTITY + model+"Model" );

            Method exMethod = clazz.getMethod("findByExample", clazzModel);
            Object object = JSON.parseObject(JSON.toJSONString(paramMap), clazzModel);
            Object invoke = exMethod.invoke(beanService,object);
            if(invoke instanceof Message){
                return (Message) invoke;
            }
            message.setCode("1");
            message.setData(invoke);
        } catch (Exception e) {
            e.printStackTrace();
            message.setCode("0");
        }
        return message;
    }

    /**
     * 通用保存
     * @param model
     * @param map
     */
    @RequestMapping(value = "/model/{model}/save")
    public Message saveEntity(@PathVariable String  model,
                           @RequestBody Map<String,Object> map){
        Message message = new Message();
        Object beanService = SpringContextUtils.getBean(model+"Service");
        try {
            model = (new StringBuilder()).append(Character.toUpperCase(model.charAt(0))).append(model.substring(1)).toString();
            Class clazzService = getClass(COM_HONHAND_ZERO_ADMIN_SERVICE + model + "Service");
            Class clazzModel = getClass(COM_HONHAND_ZERO_ADMIN_ENTITY + model+"Model" );
            Method save = clazzService.getMethod("save", BaseEntity.class);
            Object object = JSON.parseObject(JSON.toJSONString(map), clazzModel);
            save.invoke(beanService,object);
            message.setCode("1");
        }catch (Exception e){
            e.printStackTrace();
            message.setCode("0");
        }
        return message;
    }


    /**
     * 通用更新
     * @param model
     * @param map
     */
    @RequestMapping(value = "/model/{model}/update")
    public Message updateEntity(@PathVariable String  model,
                           @RequestBody Map<String,Object> map){
        Object beanService = SpringContextUtils.getBean(model+"Service");
        Message message = new Message();
        try {
            model = (new StringBuilder()).append(Character.toUpperCase(model.charAt(0))).append(model.substring(1)).toString();
            Class clazzService = getClass(COM_HONHAND_ZERO_ADMIN_SERVICE + model + "Service");
            Class clazzModel = getClass(COM_HONHAND_ZERO_ADMIN_ENTITY + model+"Model" );
            Method update = clazzService.getMethod("update", BaseEntity.class);
            Object object = JSON.parseObject(JSON.toJSONString(map), clazzModel);
            update.invoke(beanService,object);
            message.setCode("1");
        }catch (Exception e){
            e.printStackTrace();
            message.setCode("0");
        }
        return message;
    }

    /**
     * 批量merge 无事务
     * @param model
     * @param mapData
     * @return
     */
    @RequestMapping(value = "/model/{model}/batchMerge")
    public Message batchMergeEntity(@PathVariable String  model,
                           @RequestBody Map<String,List<Map<String,Object>>> mapData){
        Message message = new Message();
        Object beanService = SpringContextUtils.getBean(model+"Service");
        try {
            model = (new StringBuilder()).append(Character.toUpperCase(model.charAt(0))).append(model.substring(1)).toString();
            Class clazzService = getClass(COM_HONHAND_ZERO_ADMIN_SERVICE + model + "Service");
            Class clazzModel = getClass(COM_HONHAND_ZERO_ADMIN_ENTITY + model+"Model" );

            if(mapData.containsKey("delete") && mapData.get("delete").size()>0){
                List<Map<String, Object>> list = mapData.get("delete");
                Method delete = clazzService.getMethod("delete", String.class);
                for (Map<String, Object> map : list) {
                    Object object = JSON.parseObject(JSON.toJSONString(map), clazzModel);
                    BaseEntity b = (BaseEntity) object;
                    delete.invoke(beanService,b.getId());
                }
            }

            if(mapData.containsKey("save") && mapData.get("save").size()>0){
                List<Map<String, Object>> list = mapData.get("save");
                Method save = clazzService.getMethod("save", BaseEntity.class);
                for (Map<String, Object> map : list) {
                    Object object = JSON.parseObject(JSON.toJSONString(map), clazzModel);
                    BaseEntity b = (BaseEntity) object;
                    save.invoke(beanService,b);
                }
            }

            if(mapData.containsKey("update") && mapData.get("update").size()>0){
                List<Map<String, Object>> list = mapData.get("update");
                Method save = clazzService.getMethod("update", BaseEntity.class);
                for (Map<String, Object> map : list) {
                    Object object = JSON.parseObject(JSON.toJSONString(map), clazzModel);
                    BaseEntity b = (BaseEntity) object;
                    save.invoke(beanService,b);
                }
            }

            message.setCode("1");
        }catch (Exception e){
            e.printStackTrace();
            message.setCode("0");
        }
        return message;
    }

    /**
     * 通用删除
     * @param model
     * @param ids
     */
    @RequestMapping(value = "/model/{model}/delete")
    public Message deleteEntity(@PathVariable String  model,
                             @RequestBody List<String> ids){
        Message message = new Message();
        Object beanService = SpringContextUtils.getBean(model+"Service");
        try {
            model = (new StringBuilder()).append(Character.toUpperCase(model.charAt(0))).append(model.substring(1)).toString();
            Class clazzService = getClass(COM_HONHAND_ZERO_ADMIN_SERVICE + model + "Service");
            Method delete = clazzService.getMethod("delete", String.class);
            for (String id : ids) {
                delete.invoke(beanService,id);
            }
            message.setCode("1");
        }catch (Exception e){
            e.printStackTrace();
            message.setCode("0");
        }
        return message;
    }

    /**
     * 自定义执行方法
     * @param model
     * @param method
     * @param map
     * @return
     */
    @RequestMapping(value = "/model/{model}/{method}/custom")
    public Message customEntity(@PathVariable String  model,
                                @PathVariable String  method,
                                @RequestBody Map<String,Object> map){
        Message message = new Message();
        Object beanService = SpringContextUtils.getBean(model+"Service");
        try {
            model = (new StringBuilder()).append(Character.toUpperCase(model.charAt(0))).append(model.substring(1)).toString();

            String className = COM_HONHAND_ZERO_ADMIN_SERVICE + model + "Service";
            Class clazzService = getClass(className);

            Method custom = clazzService.getMethod(method, Map.class);
            Object invoke = custom.invoke(beanService, map);
            if(invoke instanceof Message){
                return (Message)invoke;
            }
            message.setData(invoke);
            message.setCode("1");
        }catch (Exception e){
            e.printStackTrace();
            message.setCode("0");
        }
        return message;
    }

    /**
     * 类缓存
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    public Class getClass(String className) throws ClassNotFoundException {
        Class clazzService = null;
        LRUCache lruCache = ZEROCacheUtil.lruCache;
        boolean exist = lruCache.containsKey(className);
        if(exist){
            clazzService = ((Class) lruCache.get(className));
        }else{
            clazzService = Class.forName(className);
            lruCache.put(className,clazzService);
        }
        return clazzService;

    }

}
